import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {
  ActionSheetController,
  AlertController,
  Events,
  LoadingController,
  ModalController,
  NavController,
  Platform,
  ToastController
} from '@ionic/angular';
import {Storage} from '@ionic/storage';
import {catchError, filter, map, mapTo, mergeMap, take, tap} from 'rxjs/internal/operators';
import {Observable, of, race, timer} from 'rxjs';
import {UtilService} from './util.service';
import {fromPromise} from 'rxjs/internal/observable/fromPromise';
import * as moment from 'moment';
import {UrlAndOPT} from '../common/url-and-opt.enum';
import {AppConfig} from '../common/app-config.enum';
import {LoginSuccess, Logout} from '../actions/auth.actions';
import * as authReducer from '../reducers/auth.reducer';
import {select, Store} from '@ngrx/store';
import {IframePageComponent} from '../components/iframe-page/iframe-page.component';
import {File} from '@ionic-native/file/ngx';
import {FileOpener} from '@ionic-native/file-opener/ngx';
import {FileTransfer, FileTransferObject} from '@ionic-native/file-transfer/ngx';
import {AppVersion} from '@ionic-native/app-version/ngx';
import {InAppBrowser} from '@ionic-native/in-app-browser/ngx';
import * as networkReducer from '../reducers/network.reducer';
import {NetworkState} from '../reducers/network.reducer';

@Injectable({
  providedIn: 'root'
})
export class HttpService {

  // 允许超时时长
  private timeout = 50000;
  // 超时后返回的字符串
  private timeoutResult = '[doRequest Timeout]';
  // post请求头
  private headers = new HttpHeaders({'Content-Type': 'application/x-www-form-urlencoded'});
  // 存储用户信息
  private userInfo: any;
  // 存储平台类型
  private deviceType: number;
  // 存储请求的原始参数
  private originalParams: any;
  // 出借流程步骤及错误码
  public readonly undoList: any[] = [
    {
      code: -102,
      step: '实名认证'
    },
    {
      code: -114,
      step: '电子签章'
    },
    {
      code: -113,
      step: '风险评估'
    }
  ];

  // 借款流程步骤
  public readonly undoList_loan: { [key: number]: any } = {
    2: {
      step: '实名认证'
    },
    3: {
      step: '会员信息'
    },
    4: {
      step: '电子签章'
    },
    5: {
      step: '借款申请'
    },
    6: {
      step: '上传资料'
    },
    7: {
      step: '初审审核'
    },
    8: {
      step: '复审审核'
    }
  };
  // 网络状态
  private networkState: NetworkState = {};

  constructor(private httpClient: HttpClient,
              private storage: Storage,
              private toastCtrl: ToastController,
              private utilService: UtilService,
              private store: Store<authReducer.AuthState>,
              private navCtrl: NavController,
              private modalCtrl: ModalController,
              private alertCtrl: AlertController,
              private actionSheetCtrl: ActionSheetController,
              private loadingCtrl: LoadingController,
              private events: Events,
              private appVersion: AppVersion,
              private file: File,
              private fileOpener: FileOpener,
              private fileTransfer: FileTransfer,
              private iab: InAppBrowser,
              private platform: Platform
  ) {
    // 侦听网络状态变化
    this.store.pipe(select(networkReducer.getNetwork))
      .subscribe(networkState => {
        this.networkState = networkState;
      });
  }

  // 清除存储的用户信息
  async clearUserInfo() {
    await this.storage.remove(AppConfig.USER_INFO);
    await this.storage.remove(AppConfig.GESTURE_LOCK);
  }

  // 封装请求
  doRequest(OPT: number, params?: any, method?: string, timeout?: number): Observable<any> {
    if (this.networkState.status === 1) {
      // opt不存在直接返回
      if (!OPT) {
        return of(false);
      }
      // 存储原始参数（登录超时，再次发起请求时使用）
      this.originalParams = params ? {...params} : params;
      // 获取本地存储的用户信息和系统平台类型
      return fromPromise(
        Promise.all([
          this.storage.get(AppConfig.USER_INFO),
          this.storage.get(AppConfig.USER_PLATFORM)
        ])
      )
        .pipe(
          mergeMap(infoArr => {
            this.userInfo = infoArr[0];
            this.deviceType = infoArr[1];
            // 初始化params
            params = params || {};
            // 获取设置超时的请求
            return this.getTimeOver$(
              this.getNewParams(OPT, this.addParams(this.userInfo, this.deviceType, params)),
              method,
              timeout
            );
          }),
          tap(res => {
            console.log('doRequest返回数据:', res); // 打印返回的所有数据
          }),
          mergeMap(result => {
            return this.refreshUserId(result, OPT, method, timeout); // 判断登录是否超时
          }),
          take(1),
          filter(r => r),
          map((result: any) => {
            let obj: any = false;
            if (typeof result === 'object') {
              if (result.code > 0) { // 请求成功
                obj = result;
              } else {
                this.showToast(result['msg']);
              }
            } else if (result === this.timeoutResult) {
              this.showToast('请求超时');
            }
            return obj;
          }),
          catchError(() => {
            this.showToast('系统正忙，请稍候重试：）');
            return of(false);
          })
        );
    }
  }

  // 执行版本检测
  async detectionUpgrade(isShowToast = false) {
    if (this.isMobile()) { // 真机环境
      const obj = await this.doRequest(UrlAndOPT.app_version).toPromise(); // 远程获取最新版本号及是否强制升级
      if (obj) {
        const currVersionCode = await this.appVersion.getVersionNumber();
        if (obj['version'] > currVersionCode) {
          console.log('当前APP版本' + currVersionCode);
          console.log('最新APP版本' + obj['version']);
          console.log('是否强制升级' + obj['promotionType']);
          // 获取APP升级地址
          const pathObj = await this.doRequest(UrlAndOPT.app_upgrade).toPromise();
          if (pathObj) {
            if (obj['promotionType']) { // 如果强制升级
              await this.downloadApp(pathObj['path']);
            } else {
              const alert = await this.alertCtrl.create({
                header: '提示',
                message: '发现新版本,是否立即升级？',
                buttons: [
                  {
                    text: '取消',
                    role: 'cancel',
                    cssClass: 'secondary'
                  }, {
                    text: '确定',
                    handler: () => {
                      this.downloadApp(pathObj['path']);
                    }
                  }
                ]
              });
              await alert.present();
            }
          }
        } else {
          console.log('当前已是最新版本');
          if (isShowToast) {
            await this.showToast('当前已是最新版本');
          }
        }
      }
    }
  }

  // 下载APP
  private async downloadApp(path: string) {
    if (this.isAndroid()) { // Android平台
      const loading = await this.loadingCtrl.create({
        message: '应用更新中，请勿关闭...'
      });
      await loading.present();
      // 设置手机下载路径
      const target = this.file.externalDataDirectory + 'shengrongdai_cgb.apk';
      const fileTransferObject: FileTransferObject = this.fileTransfer.create();
      console.log('升级地址：', path);
      fileTransferObject.download(path, target) // 下载APK
        .then(entry => {
          console.log('APP下载完成: ' + entry.toURL());
          // 下载后打开
          this.fileOpener.open(entry.toURL(), 'application/vnd.android.package-archive')
            .then(() => console.log('App打开'))
            .catch(e => console.log('App打开出错！', e));
          loading.dismiss();
        })
        .catch(() => {
          loading.dismiss();
          this.showToast('下载失败');
        });
    } else if (this.isIos()) { // IOS平台
      this.openUrlByBrowser(path);
    }
  }

  // 打开浏览器
  private openUrlByBrowser(path: string): void {
    this.iab.create(path, '_system');
    console.log('IOS打开链接：' + path);
  }

  // 是否真机环境
  private isMobile(): boolean {
    return this.platform.is('mobile') && !this.platform.is('mobileweb');
  }

  // 是否Android环境
  private isAndroid(): boolean {
    return this.isMobile() && this.platform.is('android');
  }

  // 是否IOS环境
  private isIos(): boolean {
    return this.isMobile() && (this.platform.is('ios') || this.platform.is('ipad') || this.platform.is('iphone'));
  }

  // 如果登录超时，重新执行登录，获取新的userId后再次发起请求
  private refreshUserId(result: any, OPT: number, method: string, timeout: number): Observable<any> {
    // 登录超时
    if (typeof result === 'object' && result['code'] === -105) {
      return this.reLogin() // 重新执行登录
        .pipe(
          tap(loginRes => console.log('重新登录结果：', loginRes)),
          mergeMap(loginRes => {
            if (typeof loginRes === 'object' && loginRes.code > 0) { // 重新登录成功
              if (loginRes[AppConfig.USER_INFO_KEY]) { // 返回了新userId
                const userInfo = {
                  ...this.userInfo,
                  [AppConfig.USER_INFO_KEY]: loginRes[AppConfig.USER_INFO_KEY]
                };
                return fromPromise(
                  this.storage.set(AppConfig.USER_INFO, userInfo) // 保存新的userId
                    .then(() => {
                      this.store.dispatch(new LoginSuccess({status: 1, userInfo: userInfo}));
                    })
                ).pipe(
                  mergeMap(() => {
                    return this.doRequest(OPT, this.originalParams, method, timeout); // 使用原始参数再次发起请求
                  }),
                );
              } else { // 未返回新userId
                return of(false);
              }
            }
            // 重新登录失败，清除用户信息，返回登录页
            return fromPromise(
              this.clearUserInfo()
                .then(() => {
                  this.navCtrl.navigateRoot('/login');
                  return false;
                })
                .catch(() => {
                  console.log('删除本地用户信息失败');
                  return false;
                })
            );
          })
        );
    }
    // idSign超时
    if (typeof result === 'object' && result['code'] === -116) {
      this.navCtrl.navigateForward(['/auth/gesture-lock', {isTimeout: true, isShowLink: true}]);
    }
    // 未超时，正常返回数据
    return of(result);
  }

  private reLogin(): Observable<any> {
    // 登录所需参数：mobile password userType deviceType
    const params = {
      mobile: this.userInfo['mobile'],
      password: this.userInfo['password'],
      userType: this.userInfo['userType'],
      deviceType: this.deviceType
    };
    return this.getTimeOver$(this.getNewParams(UrlAndOPT.auth_login, params));
  }

  // 获取加工后的参数
  private getNewParams(OPT, moreParams): any {
    // 获取当前格式化时间
    const _t = moment().format('YYYY-MM-DD HH:mm:ss');
    // 重组参数
    let newParams = {...moreParams, _t: _t, OPT: OPT};
    // 计算加密串
    newParams = {...newParams, _s: this.utilService.get_s(newParams)};
    return newParams;
  }

  // 获取设置超时后的请求对象
  private getTimeOver$(newParams, method?: string, timeout?: number): Observable<any> {
    let request$: Observable<any>;
    // 判断请求类型
    if (method && method === 'get') {
      request$ = this.httpClient.get(UrlAndOPT.HOST + UrlAndOPT.PATH, {params: newParams});
    } else {
      request$ = this.httpClient.post(
        UrlAndOPT.HOST + UrlAndOPT.PATH, null, {headers: this.headers, params: newParams}
      );
    }
    console.log('doRequest Params:', newParams);
    // 发送请求并设置超时时间
    return this.setTimeOver$(request$, timeout ? timeout : this.timeout);
  }

  // 设置超时等待
  private setTimeOver$(observable$: Observable<any>, timeout: number): Observable<any> {
    return race(observable$, timer(timeout).pipe(mapTo(this.timeoutResult)));
  }

  // 向params中添加userInfo和deviceType参数
  async getUserInfoAndDeviceType(params: any): Promise<any> {
    const infoArr = await Promise.all([
      this.storage.get(AppConfig.USER_INFO),
      this.storage.get(AppConfig.USER_PLATFORM)
    ]);
    const userInfo = infoArr[0];
    const deviceType = infoArr[1];
    return this.addParams(userInfo, deviceType, params);
  }

  // 向params添加参数
  private addParams(userInfo, deviceType, params): any {
    // 如果用户已登录，添加userId、userType和userRole参数
    if (userInfo) {
      if (userInfo[AppConfig.USER_INFO_KEY]) {
        params = {
          ...params,
          [AppConfig.USER_INFO_KEY]: userInfo[AppConfig.USER_INFO_KEY]
        };
      }
      if (userInfo[AppConfig.USER_TYPE_KEY]) {
        params = {
          ...params,
          [AppConfig.USER_TYPE_KEY]: userInfo[AppConfig.USER_TYPE_KEY]
        };
      }
      if (userInfo[AppConfig.USER_ROLE_KEY]) {
        params = {
          ...params,
          [AppConfig.USER_ROLE_KEY]: userInfo[AppConfig.USER_ROLE_KEY]
        };
      }
    }
    // 添加平台类型参数
    if (deviceType) {
      params = {...params, deviceType: deviceType};
    }
    return params;
  }

  // 序列化object类型的参数
  paramsSerialize(args: { [s: string]: any }): string {
    if (args) {
      let paramsArray: string[] = [];
      for (const key of Object.keys(args)) {
        paramsArray = [...paramsArray, key + '=' + args[key]];
      }
      return encodeURI(paramsArray.join('&'));
    }
    return '';
  }

  // 执行未完成的前置操作
  async doUndo(userRole: number, undo: any, userType?: number, params?: any) {
    switch (undo['step']) {
      case '会员信息':
        let membershipUrl = '/auth/membership-info';
        if (userType === 2) { // 是否为企业用户
          membershipUrl = '/auth/membership-info-enter';
        }
        this.navCtrl.navigateForward([membershipUrl]);
        break;
      case '实名认证':
        this.navCtrl.navigateForward(['/auth/user-account', {userRole: userRole || ''}]);
        break;
      case '电子签章':
        this.alertCtrl.create({
          header: '提示',
          message: '您尚未开通电子签章，是否立即开通？',
          buttons: [
            {
              text: '取消',
              role: 'cancel'
            }, {
              text: '确定',
              handler: () => {
                this.doRequest(UrlAndOPT.electronic_signature)
                  .subscribe(obj => {
                    if (obj) {
                      this.events.publish(AppConfig.TOPIC_UNDO_LIST);
                      this.showToast('电子签章已成功开通！');
                    }
                  });
              }
            }
          ]
        }).then(alert => alert.present());
        break;
      case '风险评估':
        // 读取用户ID
        const userInfo = await this.storage.get(AppConfig.USER_INFO);
        // 打开风险评估model
        const modal = await this.modalCtrl.create({
          component: IframePageComponent,
          componentProps: {
            title: '风险评估',
            url: UrlAndOPT.HOST + UrlAndOPT.RISK_RATING + 'sign=' + userInfo['userId']
          }
        });
        await modal.present();
        // model关闭后，发送流程状态变化通知
        await modal.onDidDismiss();
        this.events.publish(AppConfig.TOPIC_UNDO_LIST);
        break;
      case '借款申请':
        this.navCtrl.navigateForward(['/auth/loan-apply', params]);
        break;
      case '上传资料':
        this.navCtrl.navigateForward(['/auth/loan-upload', {userRole: 2}]); // 前往上传资料页面
        break;
      default:
        break;
    }
  }

  // 生成借款类型列表并显示actionsheet
  private async presentLoanTypeList(typeList: any) {
    const btnList = typeList.map(type => {
      return {
        text: type['name'],
        handler: () => {
          this.navCtrl.navigateForward(['/auth/loan-apply', {...type, userRole: 2}]);
        }
      };
    });
    btnList.push({
      text: '取消',
      role: 'cancel'
    });
    const actionSheet = await this.actionSheetCtrl.create({
      header: '选择借款类型',
      buttons: btnList
    });
    await actionSheet.present();
  }

  // 显示通知消息
  private async showToast(msg) {
    const toast = await this.toastCtrl.create({
      message: msg || '请求数据失败',
      position: AppConfig.TOAST_POSITION,
      duration: AppConfig.TOAST_DURATION * 1
    });
    return toast.present();
  }

  async getUserStatus() {
    // 获取用户迁移状态
    const userStatus = await this.doRequest(UrlAndOPT.auth_status).toPromise();
    if (!userStatus) { // 获取用户迁移状态失败，登出
      this.doLogout();
    } else {
      // 迁移用户未绑定银行卡或未重置交易密码
      if (userStatus['obj']['toBindCard'] || userStatus['obj']['toRestPWd']) {
        const alert = await this.alertCtrl.create({
          header: '提示',
          message: '盛融贷存管银行已由廊坊银行变更为陕坝银行，需要重新绑定银行卡并修改交易密码，请您设置完成后再进行操作，为您带来的不便，敬请谅解！',
          backdropDismiss: false,
          buttons: [
            {
              text: '切换账号',
              handler: () => {
                this.doLogout();
              }
            },
            {
              text: '去设置',
              handler: () => {
                if (userStatus['toBindCard']) {
                  this.addCard();
                } else {
                  this.pushPaymentPwd();
                }
              }
            }
          ]
        });
        await alert.present();
      } else {
        await this.showToast('登录成功');
        await this.navCtrl.pop();
        await this.navCtrl.navigateForward(['/auth/gesture-lock', {isShowLink: true}]);
      }
    }
  }

  // 新增银行卡
  addCard() {
    this.doRequest(UrlAndOPT.bind_card)
      .subscribe(async (obj) => {
        if (obj) {
          // 打开银行页面model
          const modal = await this.modalCtrl.create({
            component: IframePageComponent,
            componentProps: {
              title: '新增银行卡',
              url: obj['url']
            }
          });
          await modal.present();
          // 关闭model后，刷新当前面数据并通知安全中心刷新数据
          await modal.onDidDismiss();
          await this.getUserStatus();
        }
      });
  }

  // 修改交易密码
  pushPaymentPwd() {
    this.doRequest(UrlAndOPT.auth_payment_pwd)
      .subscribe(async (obj) => {
        if (obj) {
          const modal = await this.modalCtrl.create({
            component: IframePageComponent,
            componentProps: {
              title: '修改交易密码',
              url: obj['url']
            }
          });
          await modal.present();
          await modal.onDidDismiss();
          await this.getUserStatus();
        }
      });
  }

  // 执行退出登录 userId  deviceType
  private doLogout() {
    this.doRequest(UrlAndOPT.auth_logout)
      .subscribe(async (obj) => {
        if (obj) {
          await this.clearUserInfo();
          this.store.dispatch(new Logout({status: 0, userInfo: {}, response: null}));
          await this.showToast('已退出登录');
        }
      });
  }

  // 自定义ThemeableBrowser标题栏
  // public options: ThemeableBrowserOptions = {
  //   statusbar: {
  //     color: '#406DC0FF'
  //   },
  //   toolbar: {
  //     height: 56,
  //     color: '#406DC0FF'
  //   },
  //   title: {
  //     color: '#ffffffff',
  //     showPageTitle: true
  //   },
  //   backButton: {
  //     wwwImage: 'assets/imgs/left-white.png',
  //     wwwImagePressed: 'assets/imgs/left-white.png',
  //     align: 'left',
  //     event: 'backPressed'
  //   },
  //   backButtonCanClose: true
  // };

  // 开启ThemeableBrowser
  // openThemeableBrowser(url: string, title?: string): ThemeableBrowserObject {
  //   let options = {};
  //   if (title) {
  //     options = {
  //       ...this.options, title: {
  //         color: '#ffffffff',
  //         showPageTitle: false,
  //         staticText: title
  //       }
  //     };
  //   } else {
  //     options = {...this.options};
  //   }
  //   // 开启ThemeableBrowser
  //   return this.themeableBrowser.create(url, '_blank', options);
  // }

}
